﻿using System;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

namespace boda.utilities.Sockets
{
    public class WebSocketClientHelper
    {
        private ClientWebSocket _webSocket;

        public bool IsConnected => _webSocket != null && _webSocket?.State == WebSocketState.Open;

        public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, int connectTimeout = int.MaxValue)
        {
            CancellationTokenSource connectTaskCancelSource = new CancellationTokenSource();
            var connectTask = Task.Run(async () =>
            {
                while (!connectTaskCancelSource.IsCancellationRequested)
                {
                    if (!IsConnected)
                    {
                        try
                        {
                            _webSocket = new ClientWebSocket();
                            await _webSocket.ConnectAsync(uri, cancellationToken);
                        }
                        catch (Exception ex)
                        {
                            await Console.Out.WriteLineAsync(ex.Message);
                            await Task.Delay(3000);
                        }
                    }
                    else
                    {
                        connectTaskCancelSource.Cancel();
                    }
                }
            }, connectTaskCancelSource.Token);

            // Await the task to block until the operation completes and return the result
            var completedTask = await Task.WhenAny(connectTask, Task.Delay(connectTimeout));
            if (completedTask != connectTask)
            {
                connectTaskCancelSource.Cancel();
            }
        }

        public async Task SendAsync(string message, CancellationToken cancellationToken)
        {
            if (_webSocket == null || _webSocket.State != WebSocketState.Open) return;
            var buffer = new ArraySegment<byte>(System.Text.Encoding.UTF8.GetBytes(message));
            await _webSocket.SendAsync(buffer, WebSocketMessageType.Text, false, cancellationToken);
        }

        public async Task<string> ReceiveAsync(CancellationToken cancellationToken)
        {
            var buffer = new ArraySegment<byte>(new byte[4096]);
            var result = await _webSocket.ReceiveAsync(buffer, cancellationToken);
            return System.Text.Encoding.UTF8.GetString(buffer.Array, 0, result.Count);
        }

        public async Task CloseAsync(CancellationToken cancellationToken)
        {
            await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", cancellationToken);
        }
    }
}
